﻿#Include parse.ahk
#Include handleMgr.ahk

parseState := {
  START: 0x1,
  PARAM: 0x2,
  KV: 0x4,
  TARGET: 0x8,
  EXTRA: 0x10,
  OPTION: 0x20,
}

stColors := {
  normal: 'd2f1d9',
  error: 'f1d2da',
  succ: 'd2f1d9',
  warn: 'f1edd2',
  best: 'b1d7cc',
  null: 'f1d2da'
}

class Suggestion {

  static first := '', sec := '' ; 首选与次选

  static _gen(col, src, target) {
    ; 根据 已输入的字符串（src） 和 要补全的字符串（target） 得到最终串
    ; col 为当前光标位置，或者期望的位置
    if src = target or target.length < src.length
      return
    ; MsgBox JoinStr(',', src, target, col)
    ; 当使用了 ‘.’ 时，需要处理
    ; 如：c.d , code  =>  `b`bode
    sg := (i := InStr(src, '.'))
      ? ('`b'.repeat(src.length - i + 1) . target.substring(i))
      : target.substring(src.length + 1)
    return {
      c: col,
      t: sg
    }
  }

  static setCur(col, src, target) {
    Suggestion.clearCur()
    this.first := Suggestion._gen(col, src, target)
  }

  static setSec(col, src, target) {
    Suggestion.clearSec()
    this.sec := Suggestion._gen(col, src, target)
  }
  static clearCur() => this.first := ''
  static clearSec() => this.sec := ''
  static clear() => this.first := this.sec := ''

  static get(raw) {
    o := this.first || this.sec
    if !o
      return
    if this.first
      Suggestion.clearCur() ;, MsgBox(1)
    else
      Suggestion.clearSec() ;, MsgBox(2)
    pre := ''
    if raw[1] = ';' ; 排除干扰
      raw := LTrim(raw.substring(2)), pre := ';'
    if raw = ''
      return {
        t: pre o.t,
        c: o.c
      }
    i := o.c, t := o.t
    x := SubStr(raw, i + 1), r := raw.substring(1, i + 1).toChs()
    for v in t {
      if v = '`b' {
        i--
      } else { ; 普通字符
        i++, i > r.Length ? r.Push(v) : r[i] := v
      }
    }
    return {
      t: pre r.join('') x,  ; 结果字符串
      c: i + (pre = ';')  ; 光标的位置
    }
  }

  static getList(cmd, setBG) {
    r := Parse(cmd)
    Suggestion.clear()
    if !r.valid {
      switch r.code {
        case 3: ; 此时在输入关键字
          target := SubStr(cmd, InStr(cmd, '$') + 1)
          sgList := keywords.keys.filter(v => beginWith(v, target)) ; TODO: 提取函数
          if !sgList.length
            return
          Suggestion.setCur(cmd.length, target, sgList[1] '$')
          return sgList.join(',')
        default:
          setBG(stColors.error)
          return r.msg
      }
    }

    state := getCurrState(r.parsed)
    o := r.parsed
    spec := Mgr.h.Get(o.which).Spec()
    if !spec {
      setBG(stColors.warn)
      return '[' o.which ']' ' no SPEC.'
    }
    ns := getNextState(state)
    sgs := [spec.format]
    if ns & parseState.START {
      sgs.Push spec.desc
    }
    if ns & parseState.PARAM {
      if spec['params'] && spec.params.Length {
        sgs.Push spec.params.map(v => (v.name ':' v.desc '`n')).join('')
      }
    }
    if ns & parseState.KV {
      if spec['kvparams'] && spec.kvparams.Length {
        sgs.Push spec.kvparams.map(v => (v.name '=' v.desc '`n')).join('')
      }
    }
    if ns & parseState.TARGET {
      if spec.args['generator'] {
        if spec.args.cacheable { ; 是否允许缓存
          providedList := CacheFunc(spec.args.generator.postProcess)(o)
        } else {
          providedList := spec.args.generator.postProcess(o)
        }
        if IsArray(providedList) { ; 是否为有效列表
          ; 匹配
          if spec.args.generator['match'] { ; 如果指定了匹配规则
            sgList := providedList.filter(v => spec.args.generator.match(providedList, v, o.target))
          } else { ; 默认使用前缀匹配
            sgList := providedList.filter(v => beginWith(v, o.target))
          }
          if spec.args['fixed'] && !spec.args.IsOptional && !sgList.Length { ; 必须匹配提供的参数
            sgs.Push 'no match but required.'
            setBG(stColors.error)
          } else if sgList.length {
            if spec.args.generator['getSg'] {
              _sg := spec.args.generator.getSg(o.target, sgList[1])
              Suggestion.setCur(o.raw.length, o.target, _sg[1])
              Suggestion.setSec(o.raw.length, o.target, _sg[2])
            } else Suggestion.setCur(o.raw.length, o.target, sgList[1])
            sgs.Push sgList.Join()
            if sgList.length = 1 ;
              setBG(stColors.best)
          } else {
            sgs.Push spec.args.desc
          }
        }
      } else { ; 处理器不提供建议列表
        sgs.Push spec.args.desc
      }
    }
    if ns & parseState.EXTRA { ; TODO: multi检测
      if spec.extra.isEnable {
        sgs.Push spec.extra.desc
      } else {
        setBG(stColors.error)
        sgs.Push 'reject extra.'
      }
    }

    return sgs.join('`n')

    getCurrState(o) {
      if o.extra.Length
        return parseState.EXTRA
      if o.target {
        if o.raw[-1] = A_Space
          return parseState.EXTRA
        return parseState.TARGET
      }
      if o.raw[-1] = '-'
        return parseState.OPTION
      if o.kvparams.Count {
        return parseState.KV
      }
      if o.params.Length {
        return parseState.PARAM
      }
      if o.which = o.raw
        return parseState.START
      else if o.which
        return parseState.PARAM
    }

    getNextState(state) {
      switch state {
        case parseState.PARAM, parseState.KV:
          return parseState.PARAM | parseState.KV | parseState.TARGET
        case parseState.OPTION:
          return parseState.PARAM | parseState.KV
        default: return state
      }
    }

  }
}